﻿// -----------------------------------------------------------------------
// <copyright file="EnumColumn.cs" company="JSC Centido">
//  Copyright (c) JSC Centido. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------

using System.Data.Odbc;

namespace Centido.Core
{
    using System;
    using System.Collections.Generic;


    /// <summary>
    ///   An enumeration table column.
    /// </summary>
    /// <remarks>Enumeration column guarantees that it contains
    /// only those integer values that are defined as enumeration members.
    /// Each enumeration member can store a display name that can be used
    /// when building a user interface.
    /// When an enumeration member is deleted then the column is set to null
    /// for those rows that contain the value of the member to deleted.
    /// One of the enumeration members can be set as a default one.</remarks>
    /// <seealso cref="Centido.Core.Column"/>
    /// <example>
    ///   The following example shows how to use an enumeration column.
    /// <code>
    ///     using System;
    ///     using System.Data.Common;
    ///     using Centido.Core;
    /// 
    ///     class Sample
    ///     {
    ///         static void Main()
    ///         {
    ///             var domainConfig = new DomainConfiguration()
    ///             {
    ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
    ///                 DbProviderName = "MSSQLSERVER"
    ///             };
    ///         
    ///             var domain = Domain.Build(domainConfig);
    ///         
    ///             domain.DeleteAll();
    ///             
    ///             //Adding a new table
    ///             var table = domain.AddTable("my_table");
    ///             table.GrantAll();
    ///             
    ///             //Creating an enumeration column
    ///             var column = table.AddColumn("enum_column", ColumnType.Enumeration)
    ///                 as EnumColumn;
    /// 
    ///             //Creating enumeration members
    ///             column.AddMember(1).DisplayName = "The first member";
    ///             column.AddMember(2).DisplayName = "The second member";
    /// 
    ///             //Making the second member to be default
    ///             column.DefaultValue = 2;
    /// 
    ///             //Inserting two rows
    ///             var firstRowId = table.InsertRow();
    ///             var secondRowId = table.InsertRow(column.Value(1));
    /// 
    ///             Console.WriteLine("The first row: value = {0}", column.Read(firstRowId).GetInteger());
    ///             Console.WriteLine("The second row: value = {0}", column.Read(secondRowId).GetInteger());
    /// 
    ///             //Trying to insert a wrong value
    ///             try
    ///             {
    ///                 table.InsertRow(column.Value(3));
    ///             }
    ///             catch(DbException)
    ///             {
    ///                 Console.WriteLine("Inserting invalid enumeration values is not allowed");
    ///             }
    /// 
    ///             //Changing the member value
    ///             Console.WriteLine("Changing the first member value");
    /// 
    ///             column.GetMember(1).Value = 3;
    /// 
    ///             Console.WriteLine("The first row: value = {0}", column.Read(firstRowId).GetInteger());
    ///             Console.WriteLine("The second row: value = {0}", column.Read(secondRowId).GetInteger());
    ///         }
    ///     }
    /// </code>
    /// </example>
    public sealed class EnumColumn : Column, IDefaultable<int?>
    {
        /// <summary>
        ///   The default value of the column.
        /// </summary>
        private int? _defaultValue;

        /// <summary>
        ///   The availability of the enum value checking.
        /// </summary>
        private bool? _valueChecking;

        /// <summary>
        ///   Initializes a new instance of the <see cref = "Centido.Core.EnumColumn" /> class
        ///   for the specified column id and parent table.
        /// </summary>
        /// <param name = "columnId">The column id.</param>
        /// <param name = "table">The parent table.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="table"/> is null.</exception>
        internal EnumColumn(Guid columnId, Table table)
            : base(columnId, table)
        {
        }

        /// <summary>
        ///   Initializes a new instance of the <see cref = "Centido.Core.EnumColumn" /> class
        ///   for the specified column id, name, display name,
        /// description, nullability, order index, customization level and parent table.
        /// </summary>
        /// <param name="columnId">The column id.</param>
        /// <param name="table">The parent table.</param>
        /// <param name="columnName">The column name.</param>
        /// <param name="displayName">The column display name.</param>
        /// <param name="description">The column description.</param>
        /// <param name="isNotNull">The column ability to hold null values.</param>
        /// <param name="orderIndex">The column order index.</param>
        /// <param name="customizationlevel">The column customization level.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="table"/> is null.</exception>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="columnName"/> is null.</exception>
        /// <exception cref="ArgumentException">Thrown when the value of <paramref name="columnName"/> is an empty string.</exception>
        internal EnumColumn(Guid columnId, Table table,
            string columnName, string displayName,
            string description, bool isNotNull,
            int orderIndex, int customizationlevel) : base(columnId, table,
            columnName, displayName, description, isNotNull, orderIndex, customizationlevel)
        {
        }

        /// <summary>
        ///   Gets the column type.
        /// </summary>
        public override ColumnType ColumnType
        {
            get { return ColumnType.Enumeration; }
        }

        /// <summary>
        ///   Gets the column value database type.
        /// </summary>
        /// <example>
        ///   The following example shows the enumeration column value database type.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///         
        ///             domain.DeleteAll();
        ///             
        ///             //Adding a new table
        ///             var table = domain.AddTable("my_table");
        ///             
        ///             //Creating an enumeration column
        ///             var column = table.AddColumn("enum_column", ColumnType.Enumeration)
        ///                 as EnumColumn;
        ///             
        ///             Console.WriteLine("Enumeration column: value db type = {0}", column.ValueOdbcType);
        ///         }
        ///     }
        /// </code>
        /// </example>
        public override OdbcType ValueOdbcType
        {
            get { return OdbcType.Int; }
        }

        /// <summary>
        ///   Gets the enumeration members.
        /// </summary>
        /// <example>
        ///   The following example shows how to get the enumeration column members.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///         
        ///             domain.DeleteAll();
        ///             
        ///             //Adding a new table
        ///             var table = domain.AddTable("my_table");
        ///             
        ///             //Creating an enumeration column
        ///             var column = table.AddColumn("enum_column", ColumnType.Enumeration)
        ///                 as EnumColumn;
        ///             
        ///             //Adding some enumeration members
        ///             column.AddMember(1).DisplayName = "The first member";
        ///             column.AddMember(2).DisplayName = "The second member";
        ///             column.AddMember(3).DisplayName = "The third member";
        /// 
        ///             //Getting the enumeration members
        ///             foreach(var m in column.Members)
        ///                 Console.WriteLine("Enumeration member: value = {0}, display name = {1}",
        ///                     m.Value, m.DisplayName);
        ///         }
        ///     }
        /// </code>
        /// </example>
        public ICollection<EnumMember> Members
        {
            get
            {
                var resultList = new List<EnumMember>();

                Domain.DbAccess.ExecuteReader(
                    cmd =>
                    {
                        cmd.CommandText = string.Format(
                            "select {0} from {1} where {2}=?",
                            Db.Tables.EnumerationMemberList.Col.Value,
                            Domain.GetObjectFullName(Db.Tables.EnumerationMemberList.Name),
                            Db.Tables.EnumerationMemberList.Col.ColumnId);

                        cmd.Parameters.Add(Domain.DbAccess.CreateParameter("column_id", OdbcType.Binary, GetRawId()));
                    },
                    reader =>
                    {
                        var enumValue = reader.GetInteger(Db.Tables.EnumerationMemberList.Col.Value);

                        if (enumValue == null)
                            throw new DbOperationException();

                        resultList.Add(new EnumMember(this, enumValue.Value));
                    });

                return resultList;
            }
        }

        /// <summary>
        ///   Gets the backend table name.
        /// </summary>
        protected override string BackEndTableName
        {
            get { return Domain.GetObjectFullName(Db.Tables.EnumerationColumnList.Name); }
        }

        /// <summary>
        ///   Gets or sets the column default value.
        /// </summary>
        /// <remarks>The current user has to have the permission to change the schema in order to set this property.</remarks>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current user has no permission to set the property.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when trying to set the property to a value that is not a member of the enumeration.</exception>
        /// <example>
        ///   The following example shows how to set the default value of the enumeration.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///         
        ///             domain.DeleteAll();
        ///             
        ///             //Adding a new table
        ///             var table = domain.AddTable("my_table");
        ///             table.GrantAll();
        ///             
        ///             //Creating an enumeration column
        ///             var column = table.AddColumn("enum_column", ColumnType.Enumeration)
        ///                 as EnumColumn;
        ///             
        ///             //Adding some enumeration members
        ///             column.AddMember(1).DisplayName = "The first member";
        ///             column.AddMember(2).DisplayName = "The second member";
        ///             column.AddMember(3).DisplayName = "The third member";
        /// 
        ///             //Setting the default value
        ///             column.DefaultValue = 1;
        /// 
        ///             //Inserting a new row
        ///             var id = table.InsertRow();
        /// 
        ///             //Reading the inserted value
        ///             Console.WriteLine("Enumeration: inserted value = {0}", column.Read(id).GetInteger());
        ///         }
        ///     }
        /// </code>
        /// </example>
        public int? DefaultValue
        {
            get { return _defaultValue ?? (_defaultValue = DbValue.GetInteger(
                ReadProperty(Db.Tables.EnumerationColumnList.Col.DefaultValue))); }
            set
            {
                if (_defaultValue.HasValue && _defaultValue == value) return;

                Domain.DbAccess.ExecuteNonQuery(
                    cmd =>
                    {
                        cmd.CommandText = string.Format("{{call {0}(?,?)}}",
                            Domain.GetObjectFullName(Db.Procedures.SetEnumDefaultValue));

                        cmd.Parameters.Add(Domain.DbAccess.CreateParameter("a_column_id",
                            OdbcType.Binary, GetRawId()));
                        cmd.Parameters.Add(Domain.DbAccess.CreateParameter("a_default_value",
                            OdbcType.Decimal, DbValue.GetDbValue(value)));
                    });

                _defaultValue = value;
            }
        }

        /// <summary>
        ///   Retrieves the enumeration member by the specified value.
        /// </summary>
        /// <param name = "value">The specified enumeration member value.</param>
        /// <returns>Returns the enumeration member with the specified value if the one exists; otherwise returns null.</returns>
        /// <example>
        ///   The following example shows how to get an enumeration member by its value.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///         
        ///             domain.DeleteAll();
        ///             
        ///             //Adding a new table
        ///             var table = domain.AddTable("my_table");
        ///             
        ///             //Creating an enumeration column
        ///             var column = table.AddColumn("enum_column", ColumnType.Enumeration)
        ///                 as EnumColumn;
        ///             
        ///             //Adding some enumeration members
        ///             column.AddMember(1).DisplayName = "The first member";
        ///             column.AddMember(2).DisplayName = "The second member";
        ///             column.AddMember(3).DisplayName = "The third member";
        /// 
        ///             //Getting the member by its value
        ///             Console.WriteLine("Enumeration member: value = {0}, display name = {1}",
        ///                 1, column.GetMember(1).DisplayName);
        ///         }
        ///     }
        /// </code>
        /// </example>
        public EnumMember GetMember(int value)
        {
            var valueWasFound = false;

            Domain.DbAccess.ExecuteReader(
                cmd =>
                {
                    cmd.CommandText = string.Format(
                        "select 1 from {0} where {1}=? and {2}=?",
                        Domain.GetObjectFullName(Db.Tables.EnumerationMemberList.Name),
                        Db.Tables.EnumerationMemberList.Col.ColumnId,
                        Db.Tables.EnumerationMemberList.Col.Value);

                    cmd.Parameters.Add(Domain.DbAccess.CreateParameter("column_id", OdbcType.Binary, GetRawId()));
                    cmd.Parameters.Add(Domain.DbAccess.CreateParameter("value", OdbcType.Int, value));
                },
                reader => { valueWasFound = true; });

            if (valueWasFound)
                return new EnumMember(this, value);

            return null;
        }

        /// <summary>
        ///   Creates a new enumeration member with the specified value.
        /// </summary>
        /// <remarks>The current user has to have the permission to change the schema in order to execute this function.</remarks>
        /// <param name = "value">The enumeration member value.</param>
        /// <returns>Returns the newly created enumeration member.</returns>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current user has no permission to execute this function.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when there is already a member with the same value in the same enumeration column.</exception>
        /// <example>
        ///   The following example shows how to create enumeration column members.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///         
        ///             domain.DeleteAll();
        ///             
        ///             //Adding a new table
        ///             var table = domain.AddTable("my_table");
        ///             
        ///             //Creating an enumeration column
        ///             var column = table.AddColumn("enum_column", ColumnType.Enumeration)
        ///                 as EnumColumn;
        ///             
        ///             //Adding some enumeration members
        ///             column.AddMember(1).DisplayName = "The first member";
        ///             column.AddMember(2).DisplayName = "The second member";
        ///             column.AddMember(3).DisplayName = "The third member";
        /// 
        ///             //Getting the enumeration members
        ///             foreach(var m in column.Members)
        ///                 Console.WriteLine("Enumeration member: value = {0}, display name = {1}",
        ///                     m.Value, m.DisplayName);
        ///         }
        ///     }
        /// </code>
        /// </example>
        public EnumMember AddMember(int value)
        {
            Domain.DbAccess.ExecuteNonQuery(
                cmd =>
                {
                    cmd.CommandText = string.Format("{{call {0}(?,?)}}",
                        Domain.GetObjectFullName(Db.Procedures.AddEnumMember));

                    cmd.Parameters.Add(Domain.DbAccess.CreateParameter("a_column_id",
                        OdbcType.Binary, GetRawId()));
                    cmd.Parameters.Add(Domain.DbAccess.CreateParameter("a_value",
                        OdbcType.Int, value));
                });

            return new EnumMember(this, value);
        }

        /// <summary>
        ///   Deletes the specified enumeration member.
        /// </summary>
        /// <remarks>
        /// <para>The current user has to have the permission to change the schema in order to execute this function.</para>
        /// <para>Deleting of an enumeration member results in setting the column to null for those rows that contain the value of the deleted member.</para>
        /// </remarks>
        /// <param name = "enumMember">The enumeration member to be deleted.</param>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current user has no permission to execute this function.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when there is no enumeration member with such value.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when there are rows that contain the value of the specified enumeration member and the column is set to be not nullable.</exception>
        /// <example>
        ///   The following example shows how to delete an enumeration member.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///         
        ///             domain.DeleteAll();
        ///             
        ///             //Adding a new table
        ///             var table = domain.AddTable("my_table");
        ///             table.GrantAll();            
        /// 
        ///             //Creating an enumeration column
        ///             var column = table.AddColumn("enum_column", ColumnType.Enumeration)
        ///                 as EnumColumn;
        ///             
        ///             //Adding some enumeration members
        ///             column.AddMember(1);
        ///             column.AddMember(2);
        ///             column.AddMember(3);
        /// 
        ///             //Inserting two rows
        ///             var firstRowId = table.InsertRow(column.Value(1));
        ///             var secondRowId = table.InsertRow(column.Value(2));
        ///             var thirdRowId = table.InsertRow(column.Value(3));
        /// 
        ///             //Deleting the first member
        ///             column.DeleteMember(column.GetMember((1)));
        /// 
        ///             //Enumerating the enumeration members
        ///             foreach(var m in column.Members)
        ///                 Console.WriteLine("Enumeration member: value = {0}", m.Value);
        /// 
        ///             //Checking the row values
        ///             Console.WriteLine("First row: value = {0}", column.Read(firstRowId).GetInteger());
        ///             Console.WriteLine("Second row: value = {0}", column.Read(secondRowId).GetInteger());
        ///             Console.WriteLine("Third row: value = {0}", column.Read(thirdRowId).GetInteger());
        ///         }
        ///     }
        /// </code>
        /// </example>
        public void DeleteMember(EnumMember enumMember)
        {
            if (enumMember == null)
                throw new ArgumentNullException("enumMember");

            DeleteMember(enumMember.Value);
        }

        /// <summary>
        ///   Deletes an enumeration member with the specified value.
        /// </summary>
        /// <remarks>
        /// <para>The current user has to have the permission to change the schema in order to execute this function.</para>
        /// <para>Deleting of an enumeration member results in setting the column to null for those rows that contain the value of the deleted member.</para>
        /// </remarks>
        /// <param name = "value">The enumeration member value.</param>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current user has no permission to execute this function.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when there is no enumeration member with such value.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when there are rows that contain the value of the specified enumeration member and the column is set to be not nullable.</exception>
        /// <example>
        ///   The following example shows how to delete an enumeration member.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///         
        ///             domain.DeleteAll();
        ///             
        ///             //Adding a new table
        ///             var table = domain.AddTable("my_table");
        ///             table.GrantAll();            
        /// 
        ///             //Creating an enumeration column
        ///             var column = table.AddColumn("enum_column", ColumnType.Enumeration)
        ///                 as EnumColumn;
        ///             
        ///             //Adding some enumeration members
        ///             column.AddMember(1);
        ///             column.AddMember(2);
        ///             column.AddMember(3);
        /// 
        ///             //Inserting two rows
        ///             var firstRowId = table.InsertRow(column.Value(1));
        ///             var secondRowId = table.InsertRow(column.Value(2));
        ///             var thirdRowId = table.InsertRow(column.Value(3));
        /// 
        ///             //Deleting the first member
        ///             column.DeleteMember(1);
        /// 
        ///             //Enumerating the enumeration members
        ///             foreach(var m in column.Members)
        ///                 Console.WriteLine("Enumeration member: value = {0}", m.Value);
        /// 
        ///             //Checking the row values
        ///             Console.WriteLine("First row: value = {0}", column.Read(firstRowId).GetInteger());
        ///             Console.WriteLine("Second row: value = {0}", column.Read(secondRowId).GetInteger());
        ///             Console.WriteLine("Third row: value = {0}", column.Read(thirdRowId).GetInteger());
        ///         }
        ///     }
        /// </code>
        /// </example>
        public void DeleteMember(int value)
        {
            // If default value is set to the value to be deleted
            if (DefaultValue == value)
                DefaultValue = null;

            Domain.DbAccess.ExecuteNonQuery(
                cmd =>
                {
                    cmd.CommandText = string.Format("{{call {0}(?,?)}}",
                        Domain.GetObjectFullName(Db.Procedures.DeleteEnumMember));

                    cmd.Parameters.Add(Domain.DbAccess.CreateParameter("a_column_id", OdbcType.Binary, GetRawId()));
                    cmd.Parameters.Add(Domain.DbAccess.CreateParameter("a_value", OdbcType.Int, value));
                });
        }


        /// <summary>
        ///   Gets or sets the availability of the enum value checking.
        /// </summary>
        /// <remarks>
        ///   The current user has to have the permission to change the schema in order to set this property.
        /// </remarks>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current user
        /// has no permission to set this property.</exception>
        /// <example>
        ///   The following example shows how to turn the enum value checking off.
        /// <code>
        ///     using System;
        ///     using System.Data.Common;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///         
        ///             domain.DeleteAll();
        ///             
        ///             //Adding a new table
        ///             var table = domain.AddTable("my_table");
        ///             table.GrantAll();            
        /// 
        ///             //Creating an enumeration column
        ///             var column = table.AddColumn("enum_column", ColumnType.Enumeration)
        ///                 as EnumColumn;
        ///             
        ///             //Adding some enumeration members
        ///             column.AddMember(1);
        ///             column.AddMember(2);
        ///             column.AddMember(3);
        /// 
        ///             Console.WriteLine("Turning the value checking off");
        /// 
        ///             column.HasValueChecking = false;
        /// 
        ///             Console.WriteLine("Inserting an invalid value");
        /// 
        ///             var id = table.InsertRow(column.Value(5));
        /// 
        ///             Console.WriteLine("Column value = {0}", column.Read(id).GetInteger());
        /// 
        ///             try
        ///             {
        ///                 column.HasValueChecking = true;
        ///             }
        ///             catch(DbException)
        ///             {
        ///                 Console.WriteLine("Cannot turn the checking on when there are invalid values");
        ///             }            
        ///         }
        ///     }
        /// </code>
        /// </example>
        public bool HasValueChecking
        {
            get
            {
                if (_valueChecking == null)
                    _valueChecking = DbValue.GetBoolean(ReadProperty(Db.Tables.EnumerationColumnList.Col.HasValueChecking));

                return _valueChecking != null && _valueChecking.Value;
            }
            set
            {
                if (_valueChecking == value) return;

                Domain.DbAccess.ExecuteNonQuery(cmd =>
                    {
                        cmd.CommandText = string.Format("{{call {0}(?,?)}}",
                            Domain.GetObjectFullName(Db.Procedures.SetEnumValueChecking));

                        cmd.Parameters.Add(Domain.DbAccess.CreateParameter("a_column_id", OdbcType.Binary, GetRawId()));
                        cmd.Parameters.Add(Domain.DbAccess.CreateParameter("a_value_checking", OdbcType.Int, value ? 1 : 0));
                    });

                _valueChecking = value;
            }
        }


        /// <summary>
        ///   Prepares the column for removing.
        /// </summary>
        protected override void PrepareForRemoving()
        {
            IsNotNull = false;

            // Removing all members
            foreach (var member in Members)
                member.Delete();
        }

        /// <summary>
        ///   Refreshes the properties of the column.
        /// </summary>
        public override void Refresh()
        {
            base.Refresh();

            _defaultValue = null;
            _valueChecking = null;
        }


        /// <summary>
        ///   Adds a new enumeration column with the specified name to the specified table.
        /// </summary>
        /// <remarks>The current user has to have the permission to change the schema in order to execute this function.</remarks>
        /// <param name="table">The table.</param>
        /// <param name="columnName">The column name.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="table"/> is null.</exception>
        /// <exception cref="System.ArgumentNullException">Thrown when the value of <paramref name="columnName"/> is null.</exception>
        /// <exception cref="System.ArgumentException">Thrown when the value of <paramref name="columnName"/> is an empty string.</exception>
        /// <exception cref="System.ArgumentException">Thrown when the value of <paramref name="columnName"/> is not a valid identifier.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown the current user has no permission to execute this function.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when there is a column with the same name in the same user-defined table.</exception>
        /// <returns>Returns the newly created enumeration table column.</returns>
        /// <example>
        ///   The following example shows how to add a enumeration column.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///             
        ///             domain.DeleteAll();
        ///             
        ///             //Creating a new table
        ///             var table = domain.AddTable("my_table");
        /// 
        ///             //Creating a enumeration table column
        ///             var column = EnumColumn.Add(table, "my_column");
        ///         }
        ///     }
        /// </code>
        /// </example>
        public static EnumColumn Add(Table table, string columnName)
        {
            if (table == null)
                throw new ArgumentNullException("table");

            return table.AddColumn(columnName, ColumnType.Enumeration) as EnumColumn;
        }


        /// <summary>
        ///   Adds a new enumeration table column with the specified id and name to the specified table.
        /// </summary>
        /// <remarks>The current user has to have the permission to change the schema in order to execute this function.</remarks>
        /// <param name="table">The table.</param>
        /// <param name="columnId">The column id.</param>
        /// <param name="columnName">The column name.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="table"/> is null.</exception>
        /// <exception cref="System.ArgumentNullException">Thrown when the value of <paramref name="columnName"/> is null.</exception>
        /// <exception cref="System.ArgumentException">Thrown when the value of <paramref name="columnName"/> is an empty string.</exception>
        /// <exception cref="System.ArgumentException">Thrown when the value of <paramref name="columnName"/> is not a valid identifier.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown the current user has no permission to execute this function.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when there is a column with the same id or the same name in the same user-defined table.</exception>
        /// <returns>Returns the newly created enumeration table column.</returns>
        /// <example>
        ///   The following example shows how to create a enumeration table column.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///             
        ///             domain.DeleteAll();
        ///             
        ///             //Creating a new table
        ///             var table = domain.AddTable("my_table");
        /// 
        ///             //Creating a enumeration table column
        ///             var column = EnumColumn.Add(table, Guid.NewGuid(), "my_column");
        ///         }
        ///     }
        /// </code>
        /// </example>
        public static EnumColumn Add(Table table, Guid columnId, string columnName)
        {
            if (table == null)
                throw new ArgumentNullException("table");

            return table.AddColumn(columnId, columnName, ColumnType.Enumeration) as EnumColumn;
        }


        /// <summary>
        ///   Ensures that the table contains a enumeration column with the specified name.
        /// </summary>
        /// <remarks>The current user has to have the permission to change the schema in order to execute this function.</remarks>
        /// <param name="table">The table.</param>
        /// <param name="columnName">The column name.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="table"/> is null.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when trying to add a column and
        /// the current user has no permission to change the schema.</exception>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="columnName"/> is null.</exception>
        /// <exception cref="ArgumentException">Thrown when the value of <paramref name="columnName"/> is an empty string.</exception>
        /// <exception cref="ArgumentException">Thrown when the value of <paramref name="columnName"/> is not a valid identifier.</exception>
        /// <exception cref="DbOperationException">Thrown when the table already has a column with the 
        /// specified name but different column type.</exception>
        /// <returns>Returns a enumeration table column with the specified name.</returns>
        /// <example>
        ///   The following example shows how to ensure that a table has a enumeration column with the specified name.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///             
        ///             domain.DeleteAll();
        ///             
        ///             //Creating a new table
        ///             var table = domain.AddTable("my_table");
        /// 
        ///             //Creating a enumeration table column
        ///             table.AddColumn("first_column", ColumnType.Enumeration);
        /// 
        ///             //Ensuring the first column
        ///             EnumColumn.Ensure(table, "first_column");
        ///             //Ensuring the second column
        ///             EnumColumn.Ensure(table, "second_column");
        /// 
        ///             foreach(var column in table.Columns)
        ///                 Console.WriteLine("Table column: name = {0}, type = {1}", column.Name, column.ColumnType);
        ///         }
        ///     }
        /// </code>
        /// </example>
        public static EnumColumn Ensure(Table table, string columnName)
        {
            if (table == null)
                throw new ArgumentNullException("table");

            return table.EnsureColumn(columnName, ColumnType.Enumeration) as EnumColumn;
        }


        /// <summary>
        ///   Ensures that the table contains a enumeration column with the specified id and the specified name.
        /// </summary>
        /// <param name="table">The table.</param>
        /// <param name="columnId">The column id.</param>
        /// <param name="columnName">The column name.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="table"/> is null.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when trying to add a column and
        /// the current user has no permission to change the schema.</exception>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="columnName"/> is null.</exception>
        /// <exception cref="ArgumentException">Thrown when the value of <paramref name="columnName"/> is an empty string.</exception>
        /// <exception cref="ArgumentException">Thrown when the value of <paramref name="columnName"/> is not a valid identifier.</exception>
        /// <exception cref="DbOperationException">Thrown when the table already has a column with the
        /// specified id but different column name.</exception>
        /// <exception cref="DbOperationException">Thrown when the table already has a column with the 
        /// specified id but different column type.</exception>
        /// <exception cref="DbOperationException">Thrown when the table already has a column with the specified name
        /// but different column id.</exception>
        /// <returns>Returns the table column with the specified id, the specified name and the specified type.</returns>
        /// <returns>Returns the table column with the specified id, the specified name and the specified type.</returns>
        /// <example>
        ///   The following example shows how to ensure a enumeration column with the specified id and
        /// the specified name.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///             
        ///             domain.DeleteAll();
        ///             
        ///             //Creating a new table
        ///             var table = domain.AddTable("my_table");
        /// 
        ///             //Creating a table column
        ///             var columnId = Guid.NewGuid();
        ///             table.AddColumn(columnId, "first_column", ColumnType.Enumeration);
        /// 
        ///             //Ensuring the first column
        ///             EnumColumn.Ensure(table, columnId, "first_column");
        ///             //Ensuring the second column
        ///             EnumColumn.Ensure(table, Guid.NewGuid(), "second_column");
        /// 
        ///             foreach(var column in table.Columns)
        ///                 Console.WriteLine("Table column: name = {0}, type = {1}", column.Name, column.ColumnType);
        ///         }
        ///     }
        /// </code>
        /// </example>
        public static EnumColumn Ensure(Table table, Guid columnId, string columnName)
        {
            if (table == null)
                throw new ArgumentNullException("table");

            return table.EnsureColumn(columnId, columnName, ColumnType.Enumeration) as EnumColumn;
        }
    }
}